import jwt from 'jsonwebtoken';
import configManager from '#src/config/config.js';
import { logger } from '#src/common/utils/logger.js';
import { redisService } from '#src/common/services/redis/RedisService.js';

class JwtService {
    constructor() {
        this.jwtConfig = configManager.jwtConfig;
        this.blacklistPrefix = 'token:blacklist:';
    }

    /**
     * 生成JWT访问令牌
     * @param {Object} payload - 令牌载荷数据
     * @returns {string} JWT令牌
     */
    generateToken(payload) {
        return jwt.sign(payload, this.jwtConfig.secret, {
            expiresIn: this.jwtConfig.expiresIn,
            algorithm: this.jwtConfig.algorithm,
            issuer: this.jwtConfig.issuer,
            audience: this.jwtConfig.audience
        });
    }

    /**
     * 验证JWT令牌
     * @param {string} token - JWT令牌
     * @returns {Object} 解码后的数据
     */
    verifyToken(token) {
        return jwt.verify(token, this.jwtConfig.secret, {
            algorithms: [this.jwtConfig.algorithm],
            issuer: this.jwtConfig.issuer,
            audience: this.jwtConfig.audience
        });
    }

    /**
     * 生成刷新令牌
     * @param {Object} payload - 用户信息
     * @returns {string} 刷新令牌
     */
    generateRefreshToken(payload) {
        return jwt.sign(
            { id: payload.id, email: payload.email },
            this.jwtConfig.refreshSecret,
            {
                expiresIn: this.jwtConfig.refreshExpiresIn,
                issuer: this.jwtConfig.issuer
            }
        );
    }

    /**
     * 验证刷新令牌并生成新的访问令牌
     * @param {string} refreshToken - 刷新令牌
     * @returns {Object} 包含新访问令牌的对象
     */
    refreshAccessToken(refreshToken) {
        try {
            const decoded = jwt.verify(refreshToken, this.jwtConfig.refreshSecret, {
                issuer: this.jwtConfig.issuer
            });

            // 生成新的访问令牌
            const newAccessToken = this.generateToken({
                id: decoded.id,
                email: decoded.email
            });

            return {
                accessToken: newAccessToken,
                expiresIn: this.jwtConfig.expiresIn
            };
        } catch (error) {
            logger.error('刷新令牌验证失败', { error: error.message });
            throw error;
        }
    }

    /**
     * 将令牌加入黑名单
     * @param {string} token - JWT令牌
     * @param {number} expiresIn - 过期时间(秒)
     */
    async blacklistToken(token, expiresIn) {
        const key = `${this.blacklistPrefix}${token}`;
        const ttl = Math.max(Number(expiresIn) || 3600, 3600); // 确保至少1小时过期
        await redisService.setEx(key, ttl, 'invalid');
    }

    /**
     * 检查令牌是否在黑名单中
     * @param {string} token - JWT令牌
     * @returns {boolean} 是否在黑名单中
     */
    async isTokenBlacklisted(token) {
        const key = `${this.blacklistPrefix}${token}`;
        return !!(await redisService.get(key));
    }

    /**
     * 解码JWT令牌（不验证）
     * @param {string} token - JWT令牌
     * @returns {Object} 解码后的数据
     */
    decodeToken(token) {
        return jwt.decode(token);
    }
}

// 单例模式导出
const jwtService = new JwtService();
export default jwtService;
